#include "ConfigManager.h"
#include <QProcess>
#include <QFile>
#include <QDir>

#ifdef Q_WS_WIN
#include <winsock2.h>
#endif

ConfigManager::ConfigManager()
{

}

bool ConfigManager::Initialize()
{
	return (NetworkConfigInitialize() && IPNameConfigInitialize());

}

bool ConfigManager::NetworkConfigInitialize()
{
	bool init = false;
	char buf[1024];

	//download path
	FILE *fp;
	fp = fopen("../conf/downdir.txt", "rt");
	if (fp != NULL)
	{
		if (fgets(buf, 1024, fp) != NULL)
		{
			_downloadPath = new char[strlen(buf)];
			if (_downloadPath != NULL)
			{
				strcpy(_downloadPath, buf);
//				_downloadPath[strlen(buf)-1] = '\0';
				//todo : string parsing....
				init = true;
			}
		}
		fclose(fp);
	}
	//log capacity
	if (init)
	{
		fp = fopen("../conf/log.txt", "rt");
		if (fp != NULL)
		{
			if (fgets(buf, 1024, fp) != NULL)
				_logCapacity = QString(buf).toInt();
			else
				init = false;

			fclose(fp);
		}
		else
			init = false;
	}
	//log path
	if (init)
	{
		fp = fopen("../conf/logdir.txt", "rt");
		if (fp != NULL)
		{
			if (fgets(buf, 1024, fp) != NULL)
			{
				_logPath = new char[strlen(buf)];
				if (_logPath != NULL)
				{
					strcpy(_logPath, buf);
//					_logPath[strlen(buf)-1] = '\0';
				}
				else
					init = false;
			}
			else
				init = false;
			fclose(fp);
		}
		else
			init = false;
	}
	//network config
	if (init)
	{
		bool isSet = false;
		fp = fopen("../conf/network.txt", "rt");
		if (fp != NULL)
		{
			bool error = false, stop = false;
			int low = 0, col = 0;
			while (!error && !feof(fp))
			{
				if (fgets(buf, 1024, fp) != NULL)
				{
					if (!stop)
					{
						_ips[low][col] = QString(buf).toInt();
						if (col == 3)
						{
							if (low == 3)
								stop = true;
							else
							{
								low++;
								col = 0;
							}
						}
						else
							col++;
					}
					else
					{
						if (QString(buf).contains(':'))
						{
							_groupName = QString(buf).remove('\n');
							int startPos = 0;
							int colonIndex  = _groupName.indexOf(':');
							_group = _groupName.mid(startPos, colonIndex);
							_name = _groupName.right(_groupName.length() - colonIndex - 1);
						}
						else
							_netGroup = QString(buf).at(0).toAscii();
						isSet = true;
					}
				}
				else if (!isSet)
					error = true;
			}
			fclose(fp);
			if (error)
				init = false;
		}
		else
			init = false;
	}

	//Get Window size
	if (init)
	{
		FILE *fp = fopen("../conf/size.txt", "rt");
		bool error = false, set = false;
		int arr[4];
		if (fp != NULL)
		{
			char buf[10];
			int i = 0;
			while (!error && !feof(fp) && !set)
			{
				if (fgets(buf, 10, fp) != NULL)
				{
					arr[i++] = QString(buf).toInt();
					set = (i >= 4 ? true : false);
				}

				else
					error = true;
			}
			fclose(fp);
		}
		else
			error = true;
		if (!set)
			init = false;
		else
		{
			_rect.setX(arr[0]);
			_rect.setY(arr[1]);
			_rect.setWidth(arr[2]);
			_rect.setHeight(arr[3]);
		}
		qDebug() <<"Rect : " << _rect;
	}

	//Get local ip...
	if (init)
	{
		#ifdef Q_WS_WIN
		WSADATA data;
		char hostname[100];
		if (WSAStartup(MAKEWORD(2, 2), &data) == 0)
		{
			if (gethostname(hostname, sizeof(hostname)) != SOCKET_ERROR)
			{
				struct hostent *local;
				struct in_addr addr;
				local = gethostbyname(hostname);
				if (local != NULL)
				{
					memcpy(&addr, local->h_addr_list[0], sizeof(struct in_addr));
					_addr.setAddress(QString(inet_ntoa(addr)));
//					QString addrStr = _addr.toString();
//					_broadCastAddr.setAddress(addrStr.replace(addrStr.section('.', -1), "255"));
//					init = !(_addr.isNull() || _broadCastAddr.isNull());
				}
				else
					init = false;
			}
			else
				init = false;
		}
		else
			init = false;
		#else
		QString prog = "/bin/bash";
		QStringList arguments;
		arguments << "-c" << "ifconfig eth1 | grep 'inet ' | awk '{print $2}' | sed 's/addr://'";
		QProcess process;
		process.start(prog, arguments);
		process.waitForFinished();
		_addr.setAddress(QString(process.readAll()));
//		_broadCastAddr.setAddress("203.224.138.255");

		#endif
		QString addrStr = _addr.toString();
		_broadCastAddr.setAddress(addrStr.replace(addrStr.section('.', -1), "255"));
		init = !(_addr.isNull() || _broadCastAddr.isNull());
	}
	//Todo : ProcessIP
	if (init)
		ProcessIPs();

//	// check Shortcut enabled
//	if (init)
//	{
//		FILE *fp = fopen("../conf/shortcut.txt", "rt");
//		if (fp !=  NULL)
//		{
//			char ch;
//			if (fread(fp, 1, 1, *ch) == 1)
//				_shotcutEnable = (ch == '1' ? true : false);
//			else
//				init = false;
//		}
//		else
//			init = false;
//	}

	return init;
}

bool ConfigManager::IPNameConfigInitialize()
{
	bool error = false;
	FILE *fp = fopen("../conf/ip_name.txt", "rt");
	if (fp != NULL)
	{
		char buf[1024];
		_ipNames.clear();
		while (fgets(buf, 1024, fp) != NULL)
		{
			QString groupName = QString(buf).remove('\n');
			Client info;
			int colonIdx = groupName.indexOf(':');

			if (!info.addr.setAddress(groupName.mid(0, colonIdx)))
				info.addr = QHostAddress::Null;
			info.name = groupName.right(groupName.length()-colonIdx-1);
			info.group = "@";
			info.groupName = (info.group + info.name);
			_ipNames.append(info);
		}
	}
	return !error;
}

IPInfo ConfigManager::GetNetworkAddr(int number) const
{
	return _ipInfo[number];
}

int ConfigManager::GetLogCapacity() const
{
	return _logCapacity;
}

QString ConfigManager::GetDownloadPath() const
{
	return _downloadPath;
}

QString ConfigManager::GetLogPath() const
{
	return _logPath;
}

int ConfigManager::GetNetworkPort() const
{
	int port = GroupA;
	if (_netGroup == 'A')
		port = GroupA;
	else if (_netGroup == 'B')
		port = GroupB;
	else if (_netGroup == 'C')
		port = GroupC;
	else if (_netGroup == 'D')
		port = GroupD;
	else if (_netGroup == 'E')
		port = GroupE;
	else if (_netGroup == 'F')
		port = GroupF;
	qDebug() << "GetNetworkPort....";
	qDebug() << _netGroup << port;
	return port;
}

QRect ConfigManager::GetWindowSize() const
{
	return _rect;
}

void ConfigManager::SetWindowSize(int width, int height)
{
	//Todo : write to config file.. (size.txt);
	_rect.setWidth(width);
	_rect.setHeight(height);

	QString buf = QString::number(_rect.x()) + '\n' +
					QString::number(_rect.y()) + '\n' +
					QString::number(_rect.width()) + '\n' +
					QString::number(_rect.height());
	qDebug() << buf;
	SaveToFile("../conf/size.txt", "../conf/size_backup.txt", buf.toAscii().data());
}

QString ConfigManager::GetGroup() const
{
	return _group;
}

QString ConfigManager::GetName() const
{
	return _name;
}

QString ConfigManager::GetGroupName() const
{
	return (_group + ':' + _name);
}

QHostAddress ConfigManager::GetLocalAddress() const
{
	return _addr;
}

QHostAddress ConfigManager::GetBroadcastAddress() const
{
	return _broadCastAddr;
}

bool ConfigManager::IsMyInfo(QString groupName) const
{
	int colonIdx = groupName.indexOf(QChar(':'));
	return IsMyInfo(groupName.mid(0, colonIdx), groupName.right(groupName.length() - colonIdx - 1));
}

bool ConfigManager::IsMyInfo(QString group, QString name) const
{
	return (_group == group && _name == name);
}

int ConfigManager::GetIPNamesCount() const
{
	return _ipNames.count();
}

QString ConfigManager::GetIPName(int idx, bool forWidget) const
{
	if (forWidget)
		return (_ipNames.at(idx).addr.toString() + ':' + _ipNames.at(idx).name);
	else
		return _ipNames.at(idx).groupName;
}

QHostAddress ConfigManager::GetIPNameAddress(QString ipName) const
{
	bool found = false;
	QHostAddress addr = QHostAddress::Null;
	for (int i = 0; i < _ipNames.count() && !found; i++)
	{
		found = (_ipNames.at(i).groupName == ipName);
		if (found)
			addr = _ipNames.at(i).addr;
	}
	return addr;
}

char ConfigManager::GetNetworkGroup() const
{
	return _netGroup;
}

QHostAddress ConfigManager::GetIPNameAddress(int idx) const
{
	return _ipNames.at(idx).addr;
}

void ConfigManager::SaveToFile(QString fileName, QString backupName, const char *data)
{
//	bool error = true;
//	if (QFile::copy(fileName, backupName))
//	{
//		FILE *fp = fopen(fileName.toAscii().data(), "wt");
//		if (fp != NULL)
//		{
//			error = (fputs(data, fp) <= 0);
//			fclose(fp);
//		}
//	}
//	if (error)
//	{
//		if (QFile::exists(backupName))
//		{
//			// rollback...
//			QFile::remove(fileName);
//			QFile::rename(backupName, fileName);
//			qDebug() << fileName << "  rollback due to error.";
//		}
//	}
//	else
//		QFile::remove(backupName);

	bool backup = QFile::copy(fileName, backupName);
	if (SaveToFile(fileName, data))
		QFile::remove(backupName);
	else if (backup)
	{
		//rollback
		QFile::remove(fileName);
		QFile::rename(backupName, fileName);
		qDebug() << fileName << " rollbacked dued to error.";
	}

}

bool ConfigManager::SaveToFile(QString fileName, const char *data)
{
	bool error = true;
	FILE *fp = fopen(fileName.toAscii().data(), "wt");
	if (fp != NULL)
	{
		error = (fputs(data, fp) <= 0);
		fclose(fp);
	}
	return !error;
}

int ConfigManager::GetSavedGroupList(QFileInfoList &list) const
{
	QDir dir("../conf/group/");
	list = dir.entryInfoList(QDir::Files);
	return list.count();
}

int ConfigManager::GetSavedMemberList(QString gName, QStringList &list) const
{
	FILE *fp = fopen(QString("../conf/group/" + gName).toAscii().data(), "rt");
	if (fp != NULL)
	{
		char buf[100];
		while(!feof(fp))
		{
			//read line by line zzz
			if (fgets(buf, 1024, fp) != NULL)
			{
				QString str(buf);
				if (str.contains('\n'))
					str.remove('\n');
				list.append(str);
			}
		}
		fclose(fp);
	}
	return list.count();
}

int ConfigManager::SetShortcutEnable(bool enable)
{
//	_shortcutEnabled = enable;
}

bool ConfigManager::IsShortcutEnable()
{
	return _shotcutEnabled;
}

void ConfigManager::ProcessIPs()
{
	for (int i = 0; i < 4; i++)
		_ipInfo[i].addr = QHostAddress::Null;

	int row, col;
	for (row = 0; row < 4; row++)
	{
		QString addrStr = "";
		IPInfo ipInfo;
		int cnt = 0;
		for (col = 0; col < 4; col++)
		{
			if (col > 0)
			{
				addrStr.append(QString::number(_ips[row][col]) + '.');
				ipInfo.addrs[cnt++] = QString::number(_ips[row][col]);
			}
			else
				ipInfo.isSet = _ips[row][col];
		}
		addrStr.append("255");
		ipInfo.addr = QHostAddress(addrStr);
		_ipInfo[row] = ipInfo;
	}
//	_broadCastAddr.setAddress("203.224.138.255");
}

static ConfigManager g_configManager;
ConfigManager* GetConfigManager()
{
	return &g_configManager;
}
